#include "stdafx.h"
#include "MIDIInDevice.h"
#include "midi.h"
//#include <fstream.h>

//--------------------------------------------------------------------
// Using declarations
//--------------------------------------------------------------------


using midi::CMIDIInDevice;
using midi::CMIDIReceiver;
using midi::CMIDIInException;

// Opens the MIDI input device
void CMIDIInDevice::Open(UINT DeviceId)
{
	// Makes sure the previous device, if any, is closed before 
	// opening another one
	Close();

	// Open MIDI input device
	MMRESULT Result = ::midiInOpen(&m_DevHandle, DeviceId, 
		reinterpret_cast<DWORD>(MidiInProc),
		reinterpret_cast<DWORD>(this),
		CALLBACK_FUNCTION);

	// If we are able to open the device, change state
	if(Result == MMSYSERR_NOERROR)
	{
		m_State = OPENED;
	}
	// Else opening failed, throw exception
	else
	{
		throw CMIDIInException(Result);
	}
}
// Called by Windows when a MIDI input event occurs
void CALLBACK CMIDIInDevice::MidiInProc(HMIDIIN MidiIn, UINT Msg,
										DWORD_PTR Instance, DWORD_PTR Param1,
										DWORD_PTR Param2)
{
	CMIDIInDevice *Device;

	Device = reinterpret_cast<CMIDIInDevice *>(Instance);

	if(Device->m_Receiver != 0)
	{
		switch(Msg)
		{
		case MIM_DATA:      // Short message received
			Device->m_Receiver->ReceiveMsg(Param1, Param2);
			break;

		case MIM_ERROR:     // Invalid short message received
			Device->m_Receiver->OnError(Param1, Param2);
			break;
		}
	}
}

// Starts the recording process
void CMIDIInDevice::StartRecording()
{
	// Only begin recording if the MIDI input device has been opened
	if(m_State == OPENED)
	{ 
		// Change state
		m_State = RECORDING;

		// Start recording
		MMRESULT Result = ::midiInStart(m_DevHandle);

		// If recording attempt failed...
		if(Result != MMSYSERR_NOERROR)
		{
			// Revert back to opened state
			m_State = OPENED;

			// Throw exception
			throw CMIDIInException(Result);
		}
	}
}

// Stops the recording process
void CMIDIInDevice::StopRecording()
{
	// If the device is in fact recording...
	if(m_State == RECORDING)
	{
		// Change state
		m_State = OPENED;

		// Reset the MIDI input device
		
		::midiInReset(m_DevHandle);

	}
}
void CMIDIInDevice::Close()
{
    // If the device is recording, stop recording before closing the 
    // device
    if(m_State == RECORDING)
    {
        StopRecording();
    }

    // If the device is opened...
    if(m_State == OPENED)
    {
        // Close the device
        MMRESULT Result = ::midiInClose(m_DevHandle);

        // If a failure occurred, throw exception
        if(Result != MMSYSERR_NOERROR)
        {
            throw CMIDIInException(Result);
        }

        // Change state
        m_State = CLOSED;
    }
}

// Constructs CMIDIInDevice object in an closed state
CMIDIInDevice::CMIDIInDevice() :
m_Receiver(0),
m_State(CLOSED)
{
}
// Destruction
CMIDIInDevice::~CMIDIInDevice()
{
    // Close device
    Close();

}

// Registers the MIDI receiver. Returns the previous receiver.
CMIDIReceiver *CMIDIInDevice::SetReceiver(CMIDIReceiver &Receiver)
{
    CMIDIReceiver *PrevReceiver = m_Receiver;

    m_Receiver = &Receiver;

    return PrevReceiver;
}


// Gets the capabilities of a particular MIDI input device
void CMIDIInDevice::GetDevCaps(UINT DeviceId, MIDIINCAPS &Caps)
{
    MMRESULT Result = ::midiInGetDevCaps(DeviceId, &Caps, 
                                         sizeof Caps);

    // If we are not able to retrieve device capabilities, throw 
    // exception
    if(Result != MMSYSERR_NOERROR)
    {
        throw CMIDIInException(Result);
    }
}
